﻿/******************************************************************************
 *
 * @copyright:          Copyright 2011 UniSky Ltd.
 * @file:
 * @author:              kenping.liu
 * @creation:
 * @description:
 *
 * @modifications
 * date         user                description
 *
 *
 * @more-details
 *
 *****************************************************************************/
#ifndef _UNISKY_NET_H_
#define _UNISKY_NET_H_

#include "../u_inc.h"

#if !defined(WINDOWS)
#   if !defined(SOCKET)
    typedef int SOCKET;
#   endif
#   if !defined(INVALID_SOCKET)
#   define INVALID_SOCKET  (SOCKET)(~0)
#   endif
#   if !defined(SOCKET_ERROR)
#   define SOCKET_ERROR    (-1)
#   endif
#endif

U_NAMESPACE_BEGIN(u)
U_NAMESPACE_BEGIN(net)

typedef struct _st_u_req_obj_
{
    char    protoctol[16];
    char    host[32];
    UINT    port;
    char    user[32];
    char    passw[32];
    char    path[MAX_PATH];
}U_REQ_OBJ;

class INet
{
public:
    static void parse_url(U_REQ_OBJ* uri, const char* url);
    static void build_url(std::string& url, const U_REQ_OBJ* uri);

    static int  http_request(const char* locfile, const char* host, const UINT port, const char* obj, const char* post_data="");
    static int  http_request(char* buf, DWORD& count, const char* host, const UINT port, const char* obj, const char* post_data="");

    static int  ftp_get(const char* locfile, const char* host, const UINT port, const char* user, const char* passw, const char* path);
    static int  ftp_put(const char* locfile, const char* host, const UINT port, const char* user, const char* passw, const char* path);
    static int  ftp_rm(const char* host, const UINT port, const char* user, const char* passw, const char* path);
};

#define SOCKET_BUF_SIZE     0x0400      // 1024
//#define SOCKET_BUF_SIZE_MAX 0x0100000   // 1024*1024

#if defined(WINDOWS)
class WinSocketHelper
{
public:
    WinSocketHelper();
    ~WinSocketHelper();
};
#endif

class Socket
{
protected:
    Socket(bool tcp=true, const char* name="sock-noname");
    ~Socket();

public:
    static bool get_host_addr(char(& ip)[64], const char* name);
    static void fill_addr(struct sockaddr_in* sa, const char* ip, int port);

    SOCKET  createx();
    int     listenx(int port=0, const char* svc_addr="0.0.0.0");
    SOCKET  acceptx();
    bool    connectx(const char* host, int port);
    bool 	connect_timeout(const char* host, int port, struct timeval tv);
    int     sendx(const char* outbuf, UINT want);
    int     sendtox(const struct sockaddr_in* target, const char* outbuf, UINT want);
    int     sendtox(const char* dst_ip, unsigned short dst_port, const char* outbuf, UINT want);
    int     recvx(char* inbuf, const int want);
    int     recv_allx(char* inbuf, const int want);
    int     recvfromx(char* inbuf, const int want, char* src_ip, int& src_port);
    int     recvfrom_allx(char* inbuf, const int want, char* src_ip, int& src_port);
    void    closex();

    operator SOCKET () { return _sock; }

    void        set_name(const char* name="noname");
    const char* get_name() { return _name; }
    const char* last_error() { return _last_error; }
    
    bool validated() { return INVALID_SOCKET!=_sock; }
    int  port() { return _port; }
    SOCKET socketx() { return _sock; }

protected:
    void setoptx(bool is_svr=false);
    void update_port();

    int  read_socket(char* inbuf, const int want, struct sockaddr_in* src=NULL);
    int  read_socket_all(char* inbuf, const int want, struct sockaddr_in* src=NULL);

protected:
    SOCKET  _sock;
    bool    _tcp;
    char    _name[128];
    int     _port;
    char    _last_error[1024];
};

class ClientTcpSocket : public Socket
{
public:
    ClientTcpSocket(SOCKET s=INVALID_SOCKET);
    ~ClientTcpSocket();
};

// 异步 socket
//class ClientAsncTcpSocket : public Socket
//{
//protected:
//    virtual void on_connect();
//    virtual void on_recv();
//    virtual void on_send();
//    virtual void on_error();
//    virtual void on_timeout();
//};

class ServerTcpSocket : public Socket
{
public:
    ServerTcpSocket();
    ~ServerTcpSocket();
   
    ClientTcpSocket* acceptx();
};

// 增加UDP有效性的方法：
// 不要使用密集发送，适当的使用发包间隔，例如1ms
// 减少每个报文的大小，最好小于512byte
class UdpSocket : public Socket
{
public:
    UdpSocket();
    ~UdpSocket();    
};

U_NAMESPACE_END(net)
U_NAMESPACE_END(u)

#endif
